/*
 * @Author: zzy 917106840648 NJUST
 * @Date: 2020-03-1 08:55:51
 * @LastEditTime: 2020-04-01 15:49:44
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \W+compiler\LexicalAnalyzer.h
 */
#ifndef LEXICALANALYZER_H_
#define LEXICALANALYZER_H_
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <map>
#include <set>
#include <sstream>
#include <stack>
#include <vector>

#define KEYWORDMAX 50

using namespace std;
//用于记录NFA每一个状态
struct state
{
    //状态名
    string stateName;

    //构造函数 <
    bool operator<(const state& b) const
    {
        return stateName < b.stateName;
    }

    //排列状态
    void sortState()
    {
        string old = stateName;
        sort(stateName.begin(), stateName.end());
        //cout << "sortState------ old : " << old << "  new : " << stateName;
    }

    state() {}

    void set(state* s1, state* s2)  //赋值函数
    {
        s1->stateName = s2->stateName;
    }

    //重载运算符
    state& operator=(const state& s)
    {
        set(this, ( state* )&s);
    }

    //复制构造函数
    state(const state& s)
    {
        *this = s;
    }

    state(string a)
    {
        stateName = a;
    }

    state(char a)
    {
        stateName = a;
    }
};

//用于记录 NFA 转 DFA 过程中的 state转换
struct processState
{
    //原状态
    state oldState;

    //新状态
    state newState;

    //是否进行过一次 eclosure()
    bool isGetClosure;

    //是否为终态
    bool isFinal;
};

//记录边的信息
struct edge
{
    // 起始状态 终止状态 状态输入符号
    state edgeStart;
    state edgeEnd;
    char  edgeSymbol;
};

//存储所有nfa所有信息
struct Nfaunit
{
    /**
     * stateSet 有穷集  --记录状态
     * symbolSet有穷字母表 --记录输入符号
     * f 子集映射 全体映射
     * S 非空初态集
     * Z 终态集
     */
    set<state>   stateSet;
    set<char>    symbolSet;
    vector<edge> f;
    state        S;
    state        Z;

    //初始化函数
    Nfaunit()
    {
        f.clear();
        stateSet.clear();
        symbolSet.clear();
        S = state();
        Z = state();
    }

    Nfaunit(const Nfaunit& other)
        : stateSet(other.stateSet), symbolSet(other.symbolSet), f(other.f),
          S(other.S), Z(other.Z)
    {
    }

    Nfaunit& operator=(const Nfaunit& b)
    {
        if (this != &b)

        {
            stateSet  = b.stateSet;
            symbolSet = b.symbolSet;
            f         = b.f;
            S         = b.S;
            Z         = b.Z;
        }
        return *this;
    }

    Nfaunit& operator+=(const Nfaunit& b)
    {
        stateSet.insert(b.stateSet.begin(), b.stateSet.end());
        symbolSet.insert(b.symbolSet.begin(), b.symbolSet.end());
        f.insert(f.end(), b.f.begin(), b.f.end());
        return *this;
    }
};

/****  NFA ****/
class Nfa {
  public:
    Nfa();
    Nfa(const Nfa&);
    Nfaunit _data;
    Nfa&    operator=(const Nfa&);

    Nfaunit getNfa() const
    {
        return _data;
    }

  public:
    /**
     * @description:读入正规文法 或输入正规文法 并将正规文法转化为 Nfa
     * @param {type}
     * @return:
     */
    void toNfa();

    /**
     * @description: 展示Nfa
     * @param
     * @return:
     */
    void show() const;

    /**
     * @description: 更新有穷集 有穷字母集
     * @param {type}
     * @return:
     */
    void update();

    /**
     * @description: 运行。 test
     * @param {type}
     * @return:
     */
    void run();

  private:
    //可添加一系列检查 字符 文法是否合理 的函数

  private:
    int      _stateNum;
    ostream& _out;
    ifstream _in;
};

//存储所有nfa所有信息
struct Dfaunit
{
    /**
     * stateSet 有穷集  --记录状态
     * symbolSet有穷字母表 --记录输入符号
     * f 子集映射
     * S 非空初态集
     * Z 终态集
     */
    set<state>   stateSet;
    set<char>    symbolSet;
    vector<edge> f;
    state        S;
    set<state>   Z;

    //初始化函数
    Dfaunit()
    {
        f.clear();
        stateSet.clear();
        symbolSet.clear();
        S = state();
        Z.clear();
    }

    Dfaunit(const Dfaunit& other)
        : stateSet(other.stateSet), symbolSet(other.symbolSet), f(other.f),
          S(other.S), Z(other.Z)
    {
    }

    Dfaunit& operator=(const Dfaunit& b)
    {
        if (this != &b)

        {
            stateSet  = b.stateSet;
            symbolSet = b.symbolSet;
            f         = b.f;
            S         = b.S;
            Z         = b.Z;
        }
        return *this;
    }

    Dfaunit& operator+=(const Dfaunit& b)
    {
        stateSet.insert(b.stateSet.begin(), b.stateSet.end());
        symbolSet.insert(b.symbolSet.begin(), b.symbolSet.end());
        f.insert(f.end(), b.f.begin(), b.f.end());
        return *this;
    }
};

/****  DFA ****/
class Dfa {
  public:
    Dfa();
    Dfa(const Dfa&);

    Dfa& operator=(const Dfa&);

    Dfaunit getDfa() const
    {
        return _data;
    }

  public:
    Dfaunit _data;

  public:
    /**
     * @description: 展示DFA
     * @param
     * @return:
     */
    void show() const;

    /**
     * @description: 更新有穷集 有穷字母集
     * @param {type}
     * @return:
     */
    void update();

    /**
     * @description: 判断该状态是否为 终态
     * @param {type}
     * @return:
     */
    bool isFinal(state temp);

    /**
     * @description: 判断 str 是否符合 DFA
     * @param {type}
     * @return:
     */
    bool isDfa(string str);

    /**
     * @description: 运行 test
     * @param {type}
     * @return:
     */
    void run();

  private:
    //可添加一系列检查 字符 文法是否合理 的函数

  private:
    ostream& _out;
    ifstream _in;
};

/**
 * @description: 去除string中重复的字符
 * @param {type}
 * @return:
 */
string removeDuplicate(string s);

/**
 * @description: 求 e 闭包运算   使用'ABC'表示 ABC三个状态的集合
 * @param state t 代表 状态 -> 起始状态 或 processState的newState
 *        Nfa nfa 为当前操作的 NFA
 * @return:
 */
state eclosure(state t, Nfa& nfa);

/**
 * @description: 求得 T 通过 symbol 可以到达的 状态
 * @param state t 代表 第一次 eclosure后的状态集合 此时为 "集合"!
 * @return:
 */
state moveI(state t, Nfa& nfa, char symbol);

/**
 * @description:实现NFA to DFA 的转换
 * @param {type}
 * @return:
 */
void NFA2DFA(Nfa& nfa, Dfa& dfa);

/**
 * 此处开始进行 词法分析器 分析部分
 * 对五类 token 进行识别 包括：关键词，标识符，常量，限定符，运算符
 *
 * 关键词 key：0--16
 * return for while break continue if else default
 *    r     f   w    b     c      i    e     d
 *
 * unsigned long int float double char bool void string
 *    u       g   t    o      d      a   l     v    s
 *
 * 标识符 identifier 变量 : ---> 18  z
 * 由字母+数组或_+数字/字母
 * 用来表示各种名字，如变量名，数组名，过程名等等。
 *
 * 常量 const: ---->19  y
 * 最好能区分类型 doublw float int 科学计数法 复数 bool ""字符串型
 * 符号数、小数、科学计数法、复数(数字+数字i)
 *
 * 限定符 : 界符--->20
 * () {} [] , ;
 *
 * 运算符：
 * 单目运算符 : ---->21
 *              + - * / ! % ~ & | ^ =
 * 双目运算符 : ---->22
 *             ++ -- || <= >= != == += -= /= *=
 *
 * 注释 ：---->23
 * 识别 # 为注释直接省略 可直接放在关键词中
 */

/**
 * @description: 将得到的keyword 的返回值 转化为 string
 * @param {type}
 * @return:
 */
string key2out(int i);

//判断是否为keyword
/**
 * @description: 转换keyword 输出token时使用
 * @param {type}
 * @return: 0-16为正确 -1为错误
 */
int toKeyword(char str[]);

/**
 * @description: 判断是否为整数
 * @param {type}
 * @return:
 */
bool isInteger(char a);

/**
 * @description: 判断是否为字母 大小写字母
 * @param {type}
 * @return:
 */
bool isLetter(char a);

/**
 * @description: 判断是否为 keyword
 * @param {type}
 * @return:
 */
bool isKeyword(const char a[]);

/**
 * @description: 判断是否为 单目运算符
 * @param {type}
 * @return:
 */
bool isSingleOperator(char a);

/**
 * @description: 判断是否为 双目运算符
 * @param {type}
 * @return:
 */
bool isDoubleOperator(char a[]);

/**
 * @description: 判断是否为界符
 * @param {type}
 * @return:
 */
bool isDelimiter(char a);

/**
 * @description: 对输入的 源代码进行 分析
 * @param {type}
 * @return:
 */
void analyze(Dfa& dfa);

/**
 * @description: 将得到的keyword 的返回值 转化为 string
 * @param {type}
 * @return:
 */
string key2out(int i);

/**
 * @description: 打开文件
 * @param {type}
 * @return:
 */
void fileOpen();

/**
 * @description: 关闭文件
 * @param {type}
 * @return:
 */
void fileClose();

#endif  // !LEXICALANALYZER_H_